﻿// Copyright (c) Stephan Tolksdorf 2007-2009
// License: Simplified BSD License. See accompanying documentation.

module FParsec.Error

#nowarn "61" // "The containing type can use 'null' as a representation value for its nullary union case. This member will be compiled as a static member."

type ErrorMessage =
     /// Parsers report this `ErrorMessage` when the input does not match the expected input.
     /// The string argument describes the expected input.
     /// This error message can be generated with the labeling operator `<?>`.
     | Expected of string

     // Having specialized union cases for string constants allows users to customize the string quoting.

     /// Parsers report this `ErrorMessage` when the input does not match an expected string constant.
     /// The constructor argument is the expected string constant.
     /// This `ErrorMessage` is mainly generated by the `pchar` and `pstring` parsers and its variants.
     | ExpectedString of string

     /// Parsers report this `ErrorMessage` when the input does not match an expected case-insensitive string constant.
     /// The constructor argument is the expected string constant.
     /// This `ErrorMessage` is mainly generated by the `pstringCI` parsers and its variants.
     | ExpectedStringCI of string

     /// Parsers report this `ErrorMessage` when they encounter some unexpected input.
     /// The string argument describes the unexpected input.
     /// This `ErrorMessage` is mainly generated by the `notFollowedByL` primitive.
     | Unexpected of string

     /// Parsers report this `ErrorMessage` when they encounter an unexpected string constant.
     /// The constructor argument is the unexpected string.
     /// This `ErrorMessage` is mainly generated by the `notFollowedByChar` and `notFollowedByString` parsers.
     | UnexpectedString of string

     /// Parsers report this `ErrorMessage` when they encounter an unexpected string constant (case-insensitive).
     /// The constructor argument is the unexpected string.
     /// This `ErrorMessage` is mainly generated by the `notFollowedByStringCI` parsers.
     | UnexpectedStringCI of string

     /// Parsers report this `ErrorMessage` when an error does not fit into the other categories.
     /// The constructor argument is a string containing the error message.
     /// This error message can be generated with the `fail` and `failFatally` primitives.
     | Message of string

     /// Parsers report this `ErrorMessage` when a "compound" failed to parse.
     /// The constructor arguments are a label for the compound parser and
     /// the error (`Position` + `ErrorMessageList`) that caused the compound to fail to parse.
     /// This error message is mainly generated by the compound-labelling operator `<??>`.
     | CompoundError of string * Position * ErrorMessageList

     /// Parsers report this `ErrorMessage` when they backtracked after an error occurred.
     /// The constructor argument is the error (`Position` + `ErrorMessageList`) that occurred before the backtracking.
     /// This error message is mainly generated by the `attempt`, `>>?` and `.>>?` primitives.
     | BacktrackPoint of Position * ErrorMessageList

     /// User-defined parsers can return this `ErrorMessage` to report application-specific error data.
     /// The object argument contains the error data.
     /// To display `OtherError` values in error messages, you will have to define your own error printer,
     /// as the default printer ignores them.
     | OtherError of System.IComparable

/// Represents a list of error messages. The order of error messages in the list carries no meaning.
/// Duplicate error messages and empty messages have no influence on ordering or equality comparison
/// and are omitted when the list is converted to a set.
and [<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue);
      CustomEquality; CustomComparison>]
    ErrorMessageList  =
    | AddErrorMessage of ErrorMessage * ErrorMessageList
    | NoErrorMessages
    with
        member ToSet:   unit -> Set<ErrorMessage>

        static member OfSeq: seq<ErrorMessage> -> ErrorMessageList

        [<CompilationRepresentation(CompilationRepresentationFlags.Instance)>]
        override Equals: obj -> bool
        [<CompilationRepresentation(CompilationRepresentationFlags.Instance)>]
        override GetHashCode: unit -> int
        interface System.IComparable

        static member internal GetDebuggerDisplay: ErrorMessageList -> string

/// `expectedError label` creates an `ErrorMessageList` with a single `Expected label` message.
val expectedError:         string -> ErrorMessageList
/// `expectedStringError str` creates an `ErrorMessageList` with a single `ExpectedString str` message.
val expectedStringError:   string -> ErrorMessageList
/// `expectedStringCIError str` creates an `ErrorMessageList` with a single `ExpectedStringCI str` message.
val expectedStringCIError: string -> ErrorMessageList

/// `unexpectedError label` creates an `ErrorMessageList` with a single `Unexpected label` message.
val unexpectedError:         string -> ErrorMessageList
/// `unexpectedStringError str` creates an `ErrorMessageList` with a single `UnexpectedString str` message.
val unexpectedStringError:   string -> ErrorMessageList
/// `unexpectedStringCIError str` creates an `ErrorMessageList` with a single `UnexpectedStringCI str` message.
val unexpectedStringCIError: string -> ErrorMessageList

/// `messageError msg` creates an `ErrorMessageList` with a single `Message msg` message.
val messageError:  string -> ErrorMessageList

/// `otherError o` creates an `ErrorMessageList` with a single `OtherError o` message.
val otherError:  System.IComparable -> ErrorMessageList

/// `backtrackError state msgs` creates an `ErrorMessageList` with a single `BacktrackPoint stat.Position msgs` message,
/// except if `msgs` is already an `ErrorMessageList` with a single `BacktrackPoint(_, _)` message,
/// in which case `msgs` is returned instead.
val backtrackError:            State<'u> -> ErrorMessageList -> ErrorMessageList

/// `compoundError label state msgs` creates an `ErrorMessageList` with a single `CompoundError label state.Position msgs` message,
/// except if `msgs` is an `ErrorMessageList` with a single `BacktrackPoint(pos2, msgs2)` message,
/// in which case an `ErrorMessageList` with a single `CompoundError label pos2 msgs2` message is returned instead.
val compoundError:   string -> State<'u> -> ErrorMessageList -> ErrorMessageList

/// `concatErrorMessages error1 error2` concatenates the two error message lists `error1` and `error2`.
val concatErrorMessages: ErrorMessageList -> ErrorMessageList -> ErrorMessageList

/// `mergeErrors error1 error2` is an inlined variant of `concatErrorMessages error1 error2`
/// that avoids the call to `concatErrorMessages` if `error1` is empty (i.e. equals `NoErrorMessages`).
val
#if NOINLINE
#else
    inline
#endif
           mergeErrors: ErrorMessageList -> ErrorMessageList -> ErrorMessageList

/// `mergeErrorsIfNeeded oldState oldError newState newError` is equivalent to
/// `if newState <> State then newError else mergeErrors oldError newError`.
val
#if NOINLINE
#else
    inline
#endif
           mergeErrorsIfNeeded:    State<'u> -> ErrorMessageList
                                -> State<'u> -> ErrorMessageList -> ErrorMessageList

/// `mergeErrorsIfNeeded3 veryOldState veryOldError oldState oldError newState newError` is equivalent to
/// `mergeErrorsIfNeeded oldState (mergeErrorsIfNeeded veryOldState veryOldError oldState oldError) newState newError`.
val
#if NOINLINE
#else
    inline
#endif
           mergeErrorsIfNeeded3:    State<'u> -> ErrorMessageList
                                 -> State<'u> -> ErrorMessageList
                                 -> State<'u> -> ErrorMessageList -> ErrorMessageList

/// Represents a simple container type that brings together the position and error messages of a parser error.
[<Sealed>]
type ParserError =
    new: Position * ErrorMessageList -> ParserError

    member Position: Position
    member Error: ErrorMessageList

    /// Returns a string representation of the `ParserError`.
    override ToString: unit -> string

    /// Returns a string representation of the `ParserError`.
    ///
    /// The given `CharStream` must contain the content of the original `CharStream`
    /// for which this `ParserError` was generated (at the original indices).
    ///
    /// For each error location the printed position information is augmented
    /// with the line of text surrounding the error position, together with a '^'-marker
    /// pointing to the exact location of the error in the input stream.
    member ToString: streamWhereErrorOccurred: CharStream -> string

    /// Writes a string representation of the `ParserError` to the given `TextWriter` value.
    ///
    /// The given `CharStream` must contain the content of the original `CharStream`
    /// for which this `ParserError` was generated (at the original indices).
    ///
    /// For each error location the printed position information is augmented
    /// with the line of text surrounding the error position, together with a '^'-marker
    /// pointing to the exact location of the error in the input stream.
    member WriteTo:   textWriter: System.IO.TextWriter
                    * streamWhereErrorOccurred: CharStream
                    * ?columnWidth: int * ?initialIndention: string * ?indentionIncrement: string
                    -> unit

    /// Writes a string representation of the `ParserError` to the given `TextWriter` value.
    ///
    /// For each error position `getStreamByName` is called with the `StreamName` of the `Position`.
    /// The returned `CharStream` must be `null` or contain the content of the `CharStream` for which
    /// the error was generated (at the original indices).
    ///
    /// If `getStreamByName` returns a non-null `CharStream`, the printed error position information is
    /// augmented with the line of text surrounding the error position, together with a '^'-marker
    /// pointing to the exact location of the error in the input stream.
    member WriteTo:   textWriter: System.IO.TextWriter
                    * getStreamByName: (string -> CharStream)
                    * ?columnWidth: int * ?initialIndention: string * ?indentionIncrement: string
                    -> unit

    /// Writes a string representation of the `ParserError` to the given `TextWriter` value.
    ///
    /// The format of the position information can be customized by specifying the `positionPrinter`
    /// argument. The given function is expected to print a representation of the passed `Position` value
    /// to the passed `TextWriter` value. If possible, it should indent text lines with the passed string
    /// and take into account the maximum column count (including indention) passed as the last argument.
    member WriteTo:   textWriter: System.IO.TextWriter
                    * ?positionPrinter: (System.IO.TextWriter -> Position -> string -> int -> unit)
                    * ?columnWidth: int * ?initialIndention: string * ?indentionIncrement: string
                    -> unit

    override Equals: obj -> bool
    override GetHashCode: unit -> int
    interface System.IComparable

/// Prints the line of text surrounding the given index in the stream and
/// marks the position of the index with a caret (^) on a second line.
/// The output is indented with the given string and is restricted to the
/// given columWidth (including the indention).
[<System.Obsolete("This function will be removed in a future version of FParsec. If you want to continue to use it, please copy its source code.")>]
val printErrorLine: CharStream -> index: int64 -> System.IO.TextWriter -> indentionString: string -> columnWidth: int -> unit

/// Internal helper function that needs to be public because it gets called from inline functions.
val _raiseInfiniteLoopException: string -> State<'u> -> 'a